# -*- coding: UTF-8 -*-

"""
                 Copyright (C) 2017 - 2021  Accumulate Team                 

      Licensed under the Apache License, Version 2.0 (the "License");       
      you may not use this file except in compliance with the License.      
      You may obtain a copy of the License at                               
                 http://www.apache.org/licenses/LICENSE-2.0                 

   Unless required by applicable law or agreed to in writing, software      
   distributed under the License is distributed on an "AS IS" BASIS,        
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
   See the License for the specific language governing permissions and      
   limitations under the License.                                           
-------------------------------------------------------------------------------
 @file       uiSerial.py
 @author     Accumulate Team
 @version    1.0.0
 @date       2021-08-04
 @brief      python ui library serial component file
 @par        work platform
                 Windows
 @par        environment
                 python 3.9.1
-------------------------------------------------------------------------------
 @note                                                                      
 1. 2021-08-04    Create File                                               
"""
import sys
from PyQt5 import QtCore, QtGui, QtWidgets, QtSerialPort
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSerialPort import *
from .SerialPortWidget import Ui_SerialPortWidget

class uiSerialPort(QtWidgets.QWidget, Ui_SerialPortWidget):
    def __init__(self, parent=None):
        super().__init__()

        # UI 初始化
        self.setupUi(self)
        if parent is not None:
            self.setParent(parent)

        # 信号槽初始化
        self.__signalSoltInit()

        # 串口初始化
        self.__portInit()

    """定义信号与槽"""
    def __signalSoltInit(self):
        # 串口检测按钮
        self.freshPortButton.clicked.connect(self.__port_check)

        # 打开串口按钮
        self.ctrlPortButton.clicked.connect(self.__port_ctrl)

        # 清除当前数据
        self.clearDataButton.clicked.connect(self.__clearRecvData)

        # 导出当前数据
        self.exportDataButton.clicked.connect(self.__exportRecvData)

        self.sig_recv = pyqtSignal(list, int)
        self.sig_send = pyqtSignal()

    def __portInit(self):
        # 设置串口实例
        self.port = QSerialPort()
        self.__port_check()

        self.recvLine = QByteArray()
        self.port.readyRead.connect(self.__port_recv_callback)
        self.port.bytesWritten.connect(self.__port_send_callback)
        self.ctrlPortButton.setText('打开端口')
        
        self.txCnt = 0
        self.rxCnt = 0

    # 串口检测
    def __port_check(self):
        # 检测所有存在的串口，将信息存储在字典中
        self.serialportList.clear()
        port_list = QSerialPortInfo.availablePorts()

        if len(port_list) == 0:
            self.serialportList.addItem('无')
        else:
            for port in port_list:
                self.serialportList.addItem(port.portName())

    # 打开串口
    def __port_ctrl(self):
        if self.serialportList.currentText().strip() == '无':
            self.ctrlPortButton.setText('打开端口')
            QMessageBox.critical(self, "Port Error", "请选择串口！")
            return

        if self.port.isOpen() == 1:
            self.port.close()
            self.ctrlPortButton.setText('打开端口')
            return

        self.port.setPortName(self.serialportList.currentText().strip())
        self.port.setBaudRate(int(self.baudRates.currentText()))
        
        # 设置数据位
        dataBits = int(self.dataBits.currentIndex())
        if dataBits == 0:
            self.port.setDataBits(QSerialPort.Data7)
        else:
            self.port.setDataBits(QSerialPort.Data8)

        # 设置停止位
        stopBits = int(self.stopBits.currentIndex())
        if stopBits == 1:
            self.port.setStopBits(QSerialPort.OneAndHalfStop)
        elif stopBits == 2:
            self.port.setStopBits(QSerialPort.TwoStop)
        else:
            self.port.setStopBits(QSerialPort.OneStop)
        
        # 设置校验位
        parity = int(self.parityBits.currentIndex())
        if parity == 1:
            self.port.setParity(QSerialPort.OddParity)
        elif parity == 2:
            self.port.setParity(QSerialPort.EvenParity)
        else:
            self.port.setParity(QSerialPort.NoParity)

        # 打开端口
        status = self.port.open(QSerialPort.ReadWrite)
        if status == 0:
            QMessageBox.critical(self, "Port Error", "串口打开失败！")
            self.ctrlPortButton.setText('打开端口')
            return
        else:
            self.ctrlPortButton.setText('关闭端口')

    # 串口接收处理
    def __port_recv_callback(self):
        recvData = self.port.readAll()
        self.rxCnt += recvData.count()
        self.recvLine.append(recvData)

        temp = []
        for i in range(recvData.count()):
            temp.append(recvData[i])

        self.sig_recv.emit(temp, len(temp))

    # 串口发送处理
    def __port_send_callback(self):
        self.sig_send.emit()

    def __clearRecvData(self):
        self.recvLine.clear()
        self.rxCnt = 0
        self.txCnt = 0

    def __exportRecvData(self):
        temp = self.recvLine

    def sendData(self, data, len):
        if self.port.isOpen() == False:
            return 0

        temp = QByteArray()
        for i in data:
            temp.append(i)

        self.port.write(temp)

        self.txCnt += len

        return len

    def readData(self, len):
        temp = []

        recvLen = self.recvLine.count()
        if len > recvLen:
            len = recvLen

        for i in range(len):
            temp.append(self.recvLine[0])
            self.recvLine.remove(0, 1)

        return temp

    def canRead(self):
        return self.recvLine.count()

    def getTxCount(self):
        return self.txCnt

    def getRxCount(self):
        return self.rxCnt

# if __name__ == '__main__':
#     app = QtWidgets.QApplication(sys.argv)
#     window = uiSerialPort()
#     window.show()
#     sys.exit(app.exec_())
